#include "unp.h"
#include <sys/epoll.h>

#define FD_SIZE 1000
#define EPOLLEVENTS 100

// create socket and bind
static int socket_bind(int port);
// epoll
static void do_epoll(int listenfd);
// events deal function
static void handle_events(int epollfd, struct epoll_event *event, int num, int listenfd, char *buf);
// deal recv connection
static void handle_accept(int epollfd, int listenfd);
// read 
static void do_read(int epollfd, int fd, char *buf);
// write
static void do_write(int epollfd, int fd, char *buf);
// add event
static void add_event(int epollfd, int fd, int state);
// modify event
static void modify_event(int epollfd, int fd, int state);
//delete event
static void delete_event(int epollfd, int fd, int state);

int main(int argc, char **argv) {
	int listenfd;
	listenfd = socket_bind(9999);
	listen(listenfd, LISTENQ);
	do_epoll(listenfd);
	return 0;
}

static int socket_bind(int port) {
	int listenfd;
	struct sockaddr_in servaddr;
	listenfd = Socket(AF_INET, SOCK_STREAM, 0);
	bzero(&servaddr, sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_port = htons(port);
	servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
	Bind(listenfd, (SA*)&servaddr, sizeof(servaddr));
	return listenfd;
}

static void do_epoll(int listenfd) {
	int epollfd;
	struct epoll_event events[EPOLLEVENTS];
	int ret;
	char buf[MAXLINE];
	memset(buf, 0, MAXLINE);
	epollfd = epoll_create(FD_SIZE);
	add_event(epollfd, listenfd, EPOLLIN);
	for (;;) {
		ret = epoll_wait(epollfd, events, EPOLLEVENTS, -1);
		handle_events(epollfd, events, ret, listenfd, buf);
	}
	close(epollfd);
}

static void handle_events(int epollfd, struct epoll_event *events, int num, int listenfd, char *buf) {
	int i;
	int fd;
	for (i = 0; i < num; i++) {
		fd = events[i].data.fd;
		if ((fd == listenfd) && (events[i].events & EPOLLIN))	
			handle_accept(epollfd, listenfd);
		else if (events[i].events & EPOLLIN) 
			do_read(epollfd, fd, buf);
		else if (events[i].events & EPOLLOUT)
			do_write(epollfd, fd, buf);
	}
}

static void handle_accept(int epollfd, int listenfd) {
	int clifd;
	struct sockaddr_in cliaddr;
	socklen_t len;
	clifd = Accept(listenfd, (SA*)&cliaddr, &len);
	if (clifd != -1) {
		printf("accept a new client: %s : %d\n", inet_ntoa(cliaddr.sin_addr), cliaddr.sin_port);
		add_event(epollfd, clifd, EPOLLIN);
	}
}

static void do_read(int epollfd, int fd, char *buf) {
	int nread;
	nread = read(fd, buf, MAXLINE);
	if (nread == -1) {
		perror("read error");
		close(fd);
		delete_event(epollfd, fd, EPOLLIN);
	} else if (nread == 0) {
		fprintf(stderr, "client close.\n");
		close(fd);
		delete_event(epollfd, fd, EPOLLIN);
	} else {
		printf("read message is : %s\n", buf);
		modify_event(epollfd, fd, EPOLLOUT);
	}
}

static void do_write(int epollfd, int fd, char *buf) {
	int nwrite;
	nwrite = write(fd, buf, strlen(buf));
	if (nwrite == -1) {
		perror("write error:");
		close(fd);
		delete_event(epollfd, fd, EPOLLOUT);
	} else {
		modify_event(epollfd, fd, EPOLLIN);
	}
	memset(buf, 0, MAXLINE);
}

static void add_event(int epollfd, int fd, int state) {
	struct epoll_event ev;
	ev.events = state;
	ev.data.fd = fd;
	epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev);
}

static void delete_event(int epollfd, int fd, int state) {
	struct epoll_event ev;
	ev.events = state;
	ev.data.fd = fd;
	epoll_ctl(epollfd, EPOLL_CTL_DEL, fd, &ev);
}

static void modify_event(int epollfd, int fd, int state) {
	struct epoll_event ev;
	ev.events = state;
	ev.data.fd = fd;
	epoll_ctl(epollfd, EPOLL_CTL_MOD, fd, &ev);
}





